using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
namespace legend
{

    public class MemoryScanner
    {
        private HandleRef handler;

        private Process p;

        private List<BoyerMoore> boyerMoores = new List<BoyerMoore>();

        private List<long> baseAddrs;

        public void SetBoyerMoores(List<BoyerMoore> boyerMoores)
        {
            this.boyerMoores = boyerMoores;
        }

        public MemoryScanner(Process p, HandleRef handler):this(p,handler,new List<BoyerMoore>()) { 
            
        }
        public MemoryScanner(Process p, HandleRef handler, List<BoyerMoore> boyerMoores)
        {
            this.handler = handler;
            this.p = p;
            this.boyerMoores = boyerMoores;
        }

        public List<long> getAllBaseAddress() {

            return this.baseAddrs;
        }

        public List<long> scanBetween(UInt32 min,UInt32 max) {
        
          //获取开始时间  
            this.baseAddrs = new List<long>();
            MemoryUtil64.MEMORY_BASIC_INFORMATION64 stMBI = new MemoryUtil64.MEMORY_BASIC_INFORMATION64();
            long searchLen = Marshal.SizeOf(stMBI);
            List<long> Ptrs = new List<long>();
            try
            {
                long address = (long)p.MainModule.BaseAddress;
                // long address = 0;
                var stopAddress = p.VirtualMemorySize64;
                List<byte[]> memory = new List<byte[]>();
                List<long> memoryPtr = new List<long>();
                while (address < stopAddress)
                {
                    var infoLength = MemoryUtil64.VirtualQueryEx(this.handler, address, out var memInfo, MemoryUtil64.MEMORY_BASIC_INFORMATION64_SIZE);

                    if (infoLength == 0)
                    {
                        Mylogger.log("can not get memory for  " + p.ProcessName);
                    }

                    // if ((memInfo.State & MemoryUtil64.MEM_COMMIT) != 0 && (memInfo.Protect == 0x04 || memInfo.Protect == 0x40))
                    if ((memInfo.State & MemoryUtil64.MEM_COMMIT) != 0 && (memInfo.Protect != 0x01))

                    {
                        var buffer = MemoryUtil64.ReadBytes(this.handler, memInfo.BaseAddress, memInfo.RegionSize);
                        memory.Add(buffer);
                        memoryPtr.Add(memInfo.BaseAddress);
                        this.baseAddrs.Add(memInfo.BaseAddress);

                    }
                    address = (long)memInfo.BaseAddress + (long)memInfo.RegionSize;
                }
                memory.AsParallel<byte[]>().WithDegreeOfParallelism(8).Select((bytes, i) =>
                {
                    var basePtr = memoryPtr[i];
                    List<long> l = new List<long>();
                    for (int offset = 0; offset < bytes.Length - 4; offset++) {
                        var v = BitConverter.ToUInt32(bytes, offset);
                        if (v >= min && v <= max) {
                            l.Add(basePtr + offset);
                        }
                    }
                    return l;

                }).Where(l=>{return l.Count>0;}).ToList().ForEach(l=>{
                    Ptrs.AddRange(l);
                });


                // Parallel.For(0, memory.Count, (i, state) =>
                // {
                //     var bytes = memory[i];
                //     var basePtr = memoryPtr[i];
                //     Parallel.For(0, this.boyerMoores.Count, (j, bstate) =>
                //     {
                //         List<long> l = this.boyerMoores[j].JudgeSearchAll(bytes, baseAddr: basePtr);
                //         if (l != null && l.Count > 0)
                //         {
                //             Ptrs.AddRange(l);
                //         }

                //     });
                // });
                return Ptrs;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
                Console.WriteLine($"读取内存出错:{ex.Message}");
                return Ptrs;
            }
        
        }


        public List<long> scan()
        {

            //获取开始时间  
            this.baseAddrs = new List<long>();
            MemoryUtil64.MEMORY_BASIC_INFORMATION64 stMBI = new MemoryUtil64.MEMORY_BASIC_INFORMATION64();
            long searchLen = Marshal.SizeOf(stMBI);
            List<long> Ptrs = new List<long>();
            try
            {
                long address = (long)p.MainModule.BaseAddress;
                // long address = 0;
                var stopAddress = p.VirtualMemorySize64;
                List<byte[]> memory = new List<byte[]>();
                List<long> memoryPtr = new List<long>();
                while (address < stopAddress)
                {
                    var infoLength = MemoryUtil64.VirtualQueryEx(this.handler, address, out var memInfo, MemoryUtil64.MEMORY_BASIC_INFORMATION64_SIZE);

                    if (infoLength == 0)
                    {
                        Mylogger.log("can not get memory for  " + p.ProcessName);
                    }

                    // if ((memInfo.State & MemoryUtil64.MEM_COMMIT) != 0 && (memInfo.Protect == 0x04 || memInfo.Protect == 0x40))
                    if ((memInfo.State & MemoryUtil64.MEM_COMMIT) != 0 && (memInfo.Protect != 0x01))

                    {
                        var buffer = MemoryUtil64.ReadBytes(this.handler, memInfo.BaseAddress, memInfo.RegionSize);
                        memory.Add(buffer);
                        memoryPtr.Add(memInfo.BaseAddress);
                        this.baseAddrs.Add(memInfo.BaseAddress);

                    }
                    address = (long)memInfo.BaseAddress + (long)memInfo.RegionSize;
                }
                memory.AsParallel<byte[]>().WithDegreeOfParallelism(8).Select((bytes, i) =>
                {
                    var basePtr = memoryPtr[i];
                    List<long> l = new List<long>();
                    for (int index = 0; index < this.boyerMoores.Count; index++)
                    {
                        l.AddRange(this.boyerMoores[index].JudgeSearchAll(bytes, baseAddr: basePtr));
                    }

                    return l;

                }).Where(l=>{return l.Count>0;}).ToList().ForEach(l=>{
                    Ptrs.AddRange(l);
                });


                // Parallel.For(0, memory.Count, (i, state) =>
                // {
                //     var bytes = memory[i];
                //     var basePtr = memoryPtr[i];
                //     Parallel.For(0, this.boyerMoores.Count, (j, bstate) =>
                //     {
                //         List<long> l = this.boyerMoores[j].JudgeSearchAll(bytes, baseAddr: basePtr);
                //         if (l != null && l.Count > 0)
                //         {
                //             Ptrs.AddRange(l);
                //         }

                //     });
                // });
                return Ptrs;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
                Console.WriteLine($"读取内存出错:{ex.Message}");
                return Ptrs;
            }

        }


    }


}